/* halt.c
 *	Simple program to test whether running a user program works.
 *	
 *	Just do a "syscall" that shuts down the OS.
 *
 * 	NOTE: for some reason, user programs with global data structures 
 *	sometimes haven't worked in the Nachos environment.  So be careful
 *	out there!  One option is to allocate data structures as 
 * 	automatics within a procedure, but if you do this, you have to
 *	be careful to allocate a big enough stack to hold the automatics!
 */

#include "syscall.h"
#define Dim 	20	


void ForkTest();
void ForkTest2();
void ExecExitTest();
void ParamTest();
void SignalTest();
void BroadcastTest();
int test1;
int a[3];
int b, c;
int test2;
void WaitTest();
void cmdLineTest();
void swapFileTest();
int matmult1();
int matmult2();


int A[Dim][Dim];
int B[Dim][Dim];
int C[Dim][Dim];
int D[Dim][Dim];
int E[Dim][Dim];
int F[Dim][Dim];

int
main()
{
	/*Allocating will take a little while, I high balled it a lot*/
	
	/* These are all the tests */
	
	/*Fork(ForkTest);*/ /*Fork test*/
	
	/*ExecExitTest();*/ /*Execute and Exit test*/

	Fork(matmult1);
	Fork(matmult2);

	/*Fork(ParamTest,3);*/ /*Param test*/
	
	/* Fork(WaitTest);*/ /* Wait tests*/
	
	/* SignalTest();*/ /* Signal Test */
	/* BroadcastTest(); */ /* Broadcast Test */
	
	/*Write1Test();*/
	
	/*LockSyscallTests();*/

	/*cmdLineTest();*/

	/*swapFileTest();*/
	
	Exit(0);
    /* not reached */
}

void WaitTest()
{
	int cv = CVCreate("waitCV",6);
	int lock = LockCreate("waitLock",8);
	LockAcquire(lock);
	Wait(cv,lock);
	Write("Printing this for write\n",15,1);
}	

void SignalTest()
{
	int signalLock = LockCreate("Signal Lock",11 );
	int signalCV= CVCreate("Signal CV",9 );
	/* This one works */
	Signal(signalCV, signalLock);

	/* This one is out of bounds on the condition variable */
	Signal(-100, signalLock);

	/* This one Lock is out of bounds */
	Signal(signalCV, -100);

	/* This one both of them is out of bounds but CV should get checked first */
	Signal(-10, -10);

}
void BroadcastTest()
{
	int broadcastLock = LockCreate("Broadcast Lock",14 );
	int broadcastLockCV= CVCreate("Broadcast CV",12 );
	/* This one works */
	Broadcast(broadcastLockCV, broadcastLock);

	/* This one is out of bounds on the condition variable */
	Broadcast(-100, broadcastLock);

	/* This one Lock is out of bounds */
	Broadcast(broadcastLockCV, -100);

	/* This one both of them is out of bounds but CV should get checked first */
	Broadcast(-10, -10);

}

void ForkTest2()
{
	Exit(0);
}

void ForkTest()
{
	/*Expected Behavior
	  Three threads will be added to process -1
	  This is a print will be printed twice
	  All threads will be asleep so the program will close
	*/
	Fork(ForkTest2);
	Fork(ForkTest2);
	Exit(0);
}

void ExecExitTest()
{
	/*Expected Behavior
	  4 processes will be created and ended
	  Processes: 2 threads will be added and ended
	  Finally the program will exit when the final thread of the final
	  process is ended
	*/
	Exec("../test/matmult",15);
	Exec("../test/matmult",15);
	Exit(0);

}

void LockSyscallTests() {
	/*CASE 1: Normative. Create, acquire, release, delete. Can't release before acquire, can't acquire twice.*/
	/*making a lock*/
	int test0 = LockCreate("TESTLOCK0", 9);
	/*testing the lock's release method before acquiring it. this should result in an error message*/
	LockRelease(test0);
	/*acquiring the lock. should result in success. should be at position 0*/
	LockAcquire(test0);
	/*acquiring again for no reason at all. should reult in error*/
	LockAcquire(test0);
	/*releasing the lock i acquired. should result in success*/
	LockRelease(test0);
	/*deleting the original lock. should result in success*/
	LockDelete(test0);
	/*acquiring the deleted lock. should result in failure since the lock was deleted*/
	LockAcquire(test0);

	/*CASE 2: 2 locks existing in lock array*/
	/*making another lock*/
	
	
	test1 = LockCreate("TESTLOCK1", 9);
	/*acquiring the lock i just made. should result in success. expect  position 0*/
	LockAcquire(test1);
	/*making yet another lock*/
	
	
	test2 = LockCreate("TESTLOCK2", 9);
	/*acquiring this new lock. should result in success. expect position 1*/
	LockAcquire(test2);
}

void Write1Test() {
	char* testStr;

	/*Normative*/
	testStr = "This should print out: Printing: 22\n";
	Write(testStr, 37, 1);
	testStr = "Printing: %i\n";
	Write1(testStr, 14, 1, 22);

	/*Testing numbers of length > 2 and < 2 characters*/
	testStr = "This should print out: Printing: 9\n";
	Write(testStr, 36, 1);
	testStr = "Printing: %i\n";
	Write1(testStr, 14, 1, 9);

	testStr = "This should print out: Printing: 999\n";
	Write(testStr, 38, 1);
	testStr = "Printing: %i\n";
	Write1(testStr, 14, 1, 999);

	/*Passing negative numbers*/
	testStr = "This should print out: Printing: -4\n";
	Write(testStr, 37, 1);
	testStr = "Printing: %i\n";
	Write1(testStr, 14, 1, -4);

	/*Passing stupidly large numbers*/
	testStr = "This should print out: Printing: 1234567890\n";
	Write(testStr, 45, 1);
	testStr = "Printing: %i\n";
	Write1(testStr, 14, 1, 1234567890);

	testStr = "This should print out: Printing: -234567890\n";
	Write(testStr, 45, 1);
	testStr = "Printing: %i\n";
	Write1(testStr, 14, 1, -234567890);

	/*Printing out characters*/
	testStr = "This should print out: Printing: q\n";
	Write(testStr, 36, 1);
	testStr = "Printing: %c\n";
	Write1(testStr, 14, 1, 'q');
}

void cmdLineTest() {
	int PEvict = TestCmdLine();
	if(PEvict == 1) {
		Write("You have chosen pfifo\n", 23, 1);
	}
	else if(PEvict == 0) {
		Write("You have chosen prand\n", 23, 1);
	}
	else {
		Write("You picked neither pfifo nor prand\n", 36, 1);
	}
}

void swapFileTest() {
	TestFileIO();
}



int
matmult1()
{

    int i, j, k;

    for (i = 0; i < Dim; i++)		/* first initialize the matrices */
	for (j = 0; j < Dim; j++) {
	     A[i][j] = i;
	     B[i][j] = j;
	     C[i][j] = 0;
	}

    for (i = 0; i < Dim; i++)		/* then multiply them together */
	for (j = 0; j < Dim; j++)
            for (k = 0; k < Dim; k++)
		 C[i][j] += A[i][k] * B[k][j];

    Exit(C[Dim-1][Dim-1]);		/* and then we're done */
}



int
matmult2()
{

    int i, j, k;

    for (i = 0; i < Dim; i++)		/* first initialize the matrices */
	for (j = 0; j < Dim; j++) {
	     D[i][j] = i;
	     E[i][j] = j;
	     F[i][j] = 0;
	}

    for (i = 0; i < Dim; i++)		/* then multiply them together */
	for (j = 0; j < Dim; j++)
            for (k = 0; k < Dim; k++)
		 F[i][j] += D[i][k] * E[k][j];

    Exit(F[Dim-1][Dim-1]);		/* and then we're done */
}
